#include <stdio.h>
//1️⃣回调函数
//一个通过函数指针调用的函数，eg:
int Add(int x,int y)
{
    return x+y;
}
void test(int(*p)(int,int))
{
    printf("%d",p(10,30));
}
int main()
{
    test(Add);
    return 0;
}
//Add函数的地址作为参数传给test函数，test函数要用函数指针来接收
//而在test函数中要通过函数指针去调用Add函数，Add函数就是回调函数
//用回调函数实现8.2.c中的计算器：
void calc(int(*p)(int,int))  //就是将case后冗余的代码封装成函数
{
    int x,y;
    printf("请输入操作数：");  
    scanf("%d %d",&x,&y);
    printf("%d\n",p(x,y));
}
void menu()
{
    printf("1.add    2.sub\n");
    printf("3.mul    4.div\n");
    printf("    0.exit\n    ");
}
int Add(int x,int y)
{
    return x+y;
}
int Sub(int x,int y)
{
    return x-y;
}
int Mul(int x,int y)
{
    return x*y;
}
int Div(int x,int y)
{
    return x/y;
}
int main()
{
    int input;
    do
    {
        menu();
        printf("请选择：");
        scanf("%d",&input);
        switch(input)
        {
            case 1:
            calc(Add);
            break;
            case 2:
            calc(Sub);
            break;
            case 3:
            calc(Mul);
            break;
            case 4:
            calc(Div);
            break;
            case 0:
            printf("退出计算器\n");
            break;
            default:
            printf("选择错误，请重新选择\n");
            break;
        }
    } while(input);
    return 0;
}
//2️⃣qsort函数 （quick sort）
//是C语言中提供的一个排序函数，是基于快速排序算法思想的一种排序算法。
//好处：现成的排序算法，直接就能用。大部分情况下效率比冒泡排序高。可以排序任意类型的数据。
//使用方法：头文件：<stdlib.h>
//void qsort(void* base,size_t num,size_t size,int (*compar)(const void*,const void*));
//void* base ——base是指针，指向了被排序数组的第一个元素。因为被排序数组中元素为任意类型的数据，所以用void*；
//size_t num ——被排序数组的元素个数；
//size_t size——base指向的元素（被排序数组的第一个元素）的大小，单位是字节；
//int (*compar)(const void*,const void*) ——函数指针，指针指向的函数是对被排序数组每两个元素进行比较的函数。
//这个比较函数需要使用者自己去写，因为qsort函数要排序任意类型的数据，不同类型的数据比较方法也不同。
//这个比较函数规则：int (*compar)(const void* p1,const void* p2)
//返回值>0，p1移向p2后面；返回值<0，p1移向p2前面（相当于不移动）。
//①测试qsort函数，排序整型数组
#include <stdlib.h>
//升序
int cmp_int1(const void* p1,const void* p2)
{
    return *((int*)p1)-*((int*)p2); //p1>p2 返回值>0 ;p1<p2 返回值<0
}           //void*类型的指针不能直接解引用(见8.1.c),这里要强制类型转化
//降序
int cmp_int2(const void* p1,const void* p2)
{
    return *((int*)p2)-*((int*)p1); //p2>p1 返回值>0 ;p2<p1 返回值<0
} 
void print_arr(int arr[],int sz)
{
    int i;
    for(i=0;i<sz;i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
}
void test1()
{
    int arr[]={3,1,5,8,7,9,2,4,6,0};
    int sz=sizeof(arr)/sizeof(arr[0]);
    print_arr(arr,sz); //3 1 5 8 7 9 2 4 6 0 
    qsort(arr,sz,sizeof(arr[0]),cmp_int1);
    print_arr(arr,sz); //0 1 2 3 4 5 6 7 8 9
    qsort(arr,sz,sizeof(arr[0]),cmp_int2);
    print_arr(arr,sz); //9 8 7 6 5 4 3 2 1 0
}
int main()
{
    test1();
    return 0;
}
//②测试qsort函数，排序结构体数据
#include <string.h>
struct Stu
{
    char name[30];
    int age;
};
//按年龄排序(升序)
int cmp_str_age(const void* p1,const void* p2)
{
    return ((struct Stu*)p1)->age-((struct Stu*)p2)->age;
}
//按名字排序(升序)
int cmp_str_name(const void* p1,const void* p2)
{
    return strcmp(((struct Stu*)p1)->name,((struct Stu*)p2)->name);  
}          //strcmp返回值为int类型
void print_arr(struct Stu *p,int sz)
{
    int i;
    for(i=0;i<sz;i++)
    {
        printf("%s ",p[i].name);
        printf("%d\n",p[i].age);
    }
}
void test2()
{
    struct Stu arr[]={{"zhangsan",28},{"lisi",38},{"wangwu",18}};
    int sz=sizeof(arr)/sizeof(arr[0]);
    print_arr(arr,sz); //(1)
    //按年龄排序(升序)
    qsort(arr,sz,sizeof(arr[0]),cmp_str_age);
    print_arr(arr,sz); //(2)
    //按名字排序(升序)
    qsort(arr,sz,sizeof(arr[0]),cmp_str_name);
    print_arr(arr,sz); //(3)
}
int main()
{
    test2();
    return 0;
}
//输出：
//(1)
//zhangsan 28
//lisi 38
//wangwu 18
//(2)
//wangwu 18
//zhangsan 28
//lisi 38
//(3)
//lisi 38
//wangwu 18
//zhangsan 28
//3️⃣qsort函数模拟实现（用冒泡排序的算法逻辑）—— 泛型编程
//①整型数据
void swap(char *p1,char *p2,size_t sz)
{
    int i;
    char p;
    for(i=0;i<sz;i++)
    {
        p=*p1;
        *p1=*p2;
        *p2=p;
        p1++;
        p2++;
    }
}
void q_bubble_sort(void* base,size_t num,size_t size,int (*cmp)(const void*,const void*))
{
    int i,j;
    for(i=0;i<num-1;i++)
    {
        for(j=0;j<num-1-i;j++)
        {
            if(cmp(((char*)base+j*size),((char*)base+(j+1)*size))>0)
            {
                swap(((char*)base+j*size),((char*)base+(j+1)*size),size);
                //一个字节一个字节交换，总共要交换size个字节
            }
        }
    }
}
//升序
int cmp_int1(const void* p1,const void* p2)
{
    return *((int*)p1)-*((int*)p2); //p1>p2 返回值>0 ;p1<p2 返回值<0
}          
//降序
int cmp_int2(const void* p1,const void* p2)
{
    return *((int*)p2)-*((int*)p1); //p2>p1 返回值>0 ;p2<p1 返回值<0
} 
void print_arr(int arr[],int sz)
{
    int i;
    for(i=0;i<sz;i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
}
int main()
{
    int arr[]={3,1,5,8,7,9,2,4,6,0};
    int sz=sizeof(arr)/sizeof(arr[0]);
    print_arr(arr,sz); //3 1 5 8 7 9 2 4 6 0 
    q_bubble_sort(arr,sz,sizeof(arr[0]),cmp_int1);
    print_arr(arr,sz); //0 1 2 3 4 5 6 7 8 9
    q_bubble_sort(arr,sz,sizeof(arr[0]),cmp_int2);
    print_arr(arr,sz); //9 8 7 6 5 4 3 2 1 0
    return 0;
}
//②结构体数据
#include <string.h>
void swap(char *p1,char *p2,size_t sz)
{
    int i;
    char p;
    for(i=0;i<sz;i++)
    {
        p=*p1;
        *p1=*p2;
        *p2=p;
        p1++;
        p2++;
    }
}
void q_bubble_sort(void* base,size_t num,size_t size,int (*cmp)(const void*,const void*))
{
    int i,j;
    for(i=0;i<num-1;i++)
    {
        for(j=0;j<num-1-i;j++)
        {
            if(cmp(((char*)base+j*size),((char*)base+(j+1)*size))>0)
            {
                swap(((char*)base+j*size),((char*)base+(j+1)*size),size);
            }
        }
    }
}
struct Stu
{
    char name[30];
    int age;
};
//按年龄排序(升序)
int cmp_str_age(const void* p1,const void* p2)
{
    return ((struct Stu*)p1)->age-((struct Stu*)p2)->age;
}
//按名字排序(升序)
int cmp_str_name(const void* p1,const void* p2)
{
    return strcmp(((struct Stu*)p1)->name,((struct Stu*)p2)->name);  
}        
void print_arr(struct Stu *p,int sz)
{
    int i;
    for(i=0;i<sz;i++)
    {
        printf("%s ",p[i].name);
        printf("%d\n",p[i].age);
    }
}
int main()
{
    struct Stu arr[]={{"zhangsan",28},{"lisi",38},{"wangwu",18}};
    int sz=sizeof(arr)/sizeof(arr[0]);
    print_arr(arr,sz); //(1)
    //按年龄排序(升序)
    q_bubble_sort(arr,sz,sizeof(arr[0]),cmp_str_age);
    print_arr(arr,sz); //(2)
    //按名字排序(升序)
    q_bubble_sort(arr,sz,sizeof(arr[0]),cmp_str_name);
    print_arr(arr,sz); //(3)
    return 0;
}
//输出：
//(1)
//zhangsan 28
//lisi 38
//wangwu 18
//(2)
//wangwu 18
//zhangsan 28
//lisi 38
//(3)
//lisi 38
//wangwu 18
//zhangsan 28